﻿
#if defined(UNITY_PROCEDURAL_INSTANCING_ENABLED)
    // 声明一个 StructuredBuffer<uint>，用于接收从 CPU 传递过来的哈希值数组
    // 每个 uint 值通常代表一个实例的哈希（比如通过 xxHash 生成），用于驱动该实例的个性化效果（如位置、颜色等）
    StructuredBuffer<uint> _Hashes;
#endif

// 一个 float4 类型的全局参数，由 C# 或 MaterialPropertyBlock 传入
// 一般包含一些配置参数，比如：
//   - _Config.x → 分辨率或网格横向跨度相关的值
//   - _Config.y → 每个实例之间的间距 / 缩放
//   - _Config.z → 用于控制 Y 轴偏移或其他效果
//   - _Config.w → 可能未使用，或作为扩展参数
float4 _Config;

// =============================================
// 函数：ConfigureProcedural()
// 作用：这是一个由 Unity 自动调用的特殊函数，用于在「程序化实例化模式」下，
//       为当前正在绘制的实例（unity_InstanceID）设置其「物体到世界空间」的变换矩阵（unity_ObjectToWorld）
//       它会在每个实例的顶点/片元着色器执行之前被调用
// =============================================

void ConfigureProcedural () {
    #if defined(UNITY_PROCEDURAL_INSTANCING_ENABLED)
        // 从 _Config 中提取参数，计算当前实例在网格中的逻辑坐标 (u, v)
        // 这里的逻辑是将 unity_InstanceID（一维索引）映射回二维网格坐标
        
        // v = 当前实例所在的“行”（大致是纵向索引）
        float v = floor(_Config.y * unity_InstanceID + 0.00001);
        
        // u = 当前实例所在的“列”（大致是横向索引）
        // 公式：u = instanceID - (总列数即 _Config.x) * v
        float u = unity_InstanceID - _Config.x * v;
        
        // =========================
        // 设置 unity_ObjectToWorld 矩阵
        // 这是 Unity 内置的变量，表示：物体局部坐标 → 世界坐标的变换矩阵（float4x4）
        // 我们只设置了其中的 4 个重要分量（3个平移 + 1个缩放），其余部分保持为单位矩阵的默认值（0.0初始化后部分覆盖）
        // =========================

        // 先将整个矩阵初始化为 0.0（安全做法，避免脏数据）
        unity_ObjectToWorld = 0.0;

        // 接下来，我们手动设置该矩阵的 4 个关键分量，用于定义物体的位置和缩放：

        // _m03_m13_m23_m33 是一个 float4，对应矩阵的第 4 列，即平移向量 (Tx, Ty, Tz, 1)
        unity_ObjectToWorld._m03_m13_m23_m33 = float4(
            // Tx：X 方向的位置
            // 将 u 偏移 0.5 后缩放，让物体分布在 [-0.5, 0.5] 为中心的网格中
            _Config.y * (u + 0.5) - 0.5,

            // Ty：Y 方向的位置（通常用作高度 / 颜色 / 偏移）
            // 这里从 _Hashes 缓冲区中取出当前实例的哈希值，并提取其最高 8 位（>>24），
            // 将其映射到 [-0.5, 0.5] 范围，作为 Y 轴上的偏移 / 颜色 / 效果控制
            _Config.z * ((1.0 / 255.0) * (_Hashes[unity_InstanceID] >> 24) - 0.5),

            // Tz：Z 方向的位置
            // 类似 X，将 v 偏移 0.5 后缩放，分布在网格中
            _Config.y * (v + 0.5) - 0.5,

            // W（齐次坐标的第4个分量）始终为 1.0
            1.0
        );

        // 设置矩阵的缩放部分（对角线上 X/Y/Z 的缩放值）
        // 这里将 X/Y/Z 缩放都设为 _Config.y，表示每个实例在世界空间中占据相同的尺寸
        unity_ObjectToWorld._m00_m11_m22 = _Config.y;
    #endif
}

// =============================================
// 函数：GetHashColor()
// 作用：基于当前实例的哈希值（_Hashes[unity_InstanceID]），
//       提取 RGB 三个通道的值，生成一个 float3 颜色
//       每个实例因为哈希值不同，会显示不同的颜色
//       该函数通常用于给实例着色，实现程序化彩色可视化
// =============================================

float3 GetHashColor () {
    #if defined(UNITY_PROCEDURAL_INSTANCING_ENABLED)
        // 从 _Hashes 缓冲区中获取当前实例的哈希值（一个 uint，32 位整数）
        uint hash = _Hashes[unity_InstanceID];

        // 从这个 uint 哈希值中，分别提取：
        // - R：最低有效字节（bit 0~7）→ hash & 255
        // - G：次低有效字节（bit 8~15）→ (hash >> 8) & 255
        // - B：第三有效字节（bit 16~23）→ (hash >> 16) & 255
        // 然后将每个字节从 [0, 255] 归一化到 [0.0, 1.0]，得到一个 RGB 颜色
        return (1.0 / 255.0) * float3(
            hash & 255,            // R
            (hash >> 8) & 255,     // G
            (hash >> 16) & 255     // B
        );
    #else
        // 如果不是程序化实例化模式，返回纯白色 (1,1,1)
        return 1.0;
    #endif
}

// =============================================
// 函数：ShaderGraphFunction_float
// 作用：这是一个兼容 Unity Shader Graph 的函数接口
//       输入一个 float3（比如位置或法线），输出原样传递的 float3 和一个颜色 float3
//       该颜色由 GetHashColor() 动态计算，每个实例不同
//       通常用于在 Shader Graph 中调用，作为自定义节点的一部分
// =============================================

void ShaderGraphFunction_float (float3 In, out float3 Out, out float3 Color) {
    Out = In;               // 原样输出输入向量（比如位置）
    Color = GetHashColor(); // 输出该实例对应的哈希颜色
}

// =============================================
// 函数：ShaderGraphFunction_half
// 作用：与上面函数相同，但是使用半精度浮点（half），用于移动端优化
// =============================================

void ShaderGraphFunction_half (half3 In, out half3 Out, out half3 Color) {
    Out = In;               // 原样输出输入向量
    Color = GetHashColor(); // 输出哈希颜色（注意：这里可能需改为返回 half3，如果 GetHashColor 支持的话）
}